package com.pa.utils;

import com.pa.pojo.Difference;
import com.pa.pojo.FileFinger;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.EditList;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.HunkHeader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 郑永震
 * @date 2021/8/25 0025 11:03
 * @mail zheng_yzh@163.com
 */
public class DiffCommit {
    /**
     * 返回提交与原文件差异
     *
     * @param gitRepoPath 仓库路径
     * @param newCommit   某次提交编号
     * @throws Exception 异常
     */
    public static Difference diffFile(/*Repository repository*/ String gitRepoPath, String newCommit) throws Exception {
        Difference difference = new Difference();
        List<FileFinger> detail = new ArrayList<>();
        try (Repository repository = RepositoryRelative.configRepository(gitRepoPath)) {
            try (Git git = new Git(repository)) {
                RevCommit commit = repository.parseCommit(repository.resolve(newCommit));
                RevCommit[] parents = commit.getParents();
                String oldCommit = parents[0].getName();
                final List<DiffEntry> diffs = git.diff()
                        .setOldTree(prepareTreeParser(repository, oldCommit))
                        .setNewTree(prepareTreeParser(repository, newCommit))
                        .call();
                //统计本次提交变化文件总数
                difference.setTotal(diffs.size());
                difference.setFilePath(new ArrayList<>());
                for(DiffEntry diffEntry:diffs){
                    difference.getFilePath().add(diffEntry.getNewPath());
                    System.out.println(diffEntry.getNewPath());
                    OutputStream os = new ByteArrayOutputStream();
                    DiffFormatter matter = new DiffFormatter(os);
                    matter.setRepository(repository);
                    matter.format(diffEntry);
                    FileHeader fileHeader = matter.toFileHeader(diffEntry);
                    for(HunkHeader header:fileHeader.getHunks()){
                        FileFinger fileFinger = new FileFinger();
                        EditList edits = header.toEditList();
                        int beginA = edits.get(0).getBeginA();
                        int endA = edits.get(0).getEndA();
                        int beginB = edits.get(0).getBeginB();
                        int endB = edits.get(0).getEndB();
                        String relativePath = diffEntry.getNewPath();
                        fileFinger.setRelativePath(relativePath);
                        String name;
                        if(relativePath.lastIndexOf("/") != -1){
                           name = diffEntry.getNewPath().substring(relativePath.lastIndexOf("/")+1,relativePath.lastIndexOf("."));
                        }else{
                            name = diffEntry.getNewPath().substring(0,relativePath.lastIndexOf("."));
                        }

                        fileFinger.setFileName(name);
                        fileFinger.setChangeType(diffEntry.getChangeType());
                        fileFinger.setOldStartLine(beginA);
                        fileFinger.setOldEndLine(endA);
                        fileFinger.setNewStartLine(beginB);
                        fileFinger.setNewEndLine(endB);
                        detail.add(fileFinger);
                    }
                    difference.setDetail(detail);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return difference;
    }

    /**
     * 解析.git文件树
     * @param repository 仓库路径
     * @param objectId 提交编号
     * @return 解析树
     * @throws IOException 异常
     */
    private static AbstractTreeIterator prepareTreeParser(Repository repository, String objectId) throws IOException {
        try (RevWalk walk = new RevWalk(repository)) {
            RevCommit commit = walk.parseCommit(repository.resolve(objectId));
            RevTree revTree = walk.parseTree(commit.getTree().getId());
            CanonicalTreeParser treeParser = new CanonicalTreeParser();
            try (ObjectReader reader = repository.newObjectReader()) {
                treeParser.reset(reader, revTree.getId());
            }
            walk.dispose();
            return treeParser;
        }
    }
}
